﻿using SharpDB.Utils;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data;
using System.Dynamic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;

namespace SharpDB.DDTekOracle
{
    public static class ObjectExtension
    {
        /// <summary>
        /// 判定 对象的类型 是否是 可空类型
        /// </summary>
        /// <param name="theType">对象类型</param>
        /// <returns></returns>
        public static bool IsNullableType(this Type theType)
        {
            return (theType.IsGenericType && theType.
              GetGenericTypeDefinition().Equals
              (typeof(Nullable<>)));
        }

        /// <summary>
        /// 获取 枚举成员 EnumMemberAttribute 的Value属性值
        /// </summary>
        /// <param name="em">枚举对象</param>
        /// <returns></returns>
        public static object EnumGetValue(this Enum em)
        {
            Type type = em.GetType();
            MemberInfo[] mInfos = type.GetMembers(BindingFlags.Static | BindingFlags.Public);
            foreach (var mInfo in mInfos)
            {
                if (mInfo.Name == em.ToString())
                {
                    EnumMemberAttribute enumMember = mInfo.GetCustomAttributes(true).FirstOrDefault() as EnumMemberAttribute;
                    if (enumMember != null)
                    {
                        return Convert.ToInt32(enumMember.Value);
                    }
                    return em.ToString();
                }
            }
            return em.ToString();
        }

        /// <summary>
        /// 获取 当前 所有枚举成员
        /// </summary>
        /// <typeparam name="T">枚举类型</typeparam>
        /// <param name="em">当前枚举成员</param>
        /// <returns></returns>
        public static List<T> AllEnums<T>(this Enum em)
        {
            List<T> lstEnum = new List<T>();
            Type type = em.GetType();
            MemberInfo[] mInfos = type.GetMembers(BindingFlags.Static | BindingFlags.Public);
            foreach (var mInfo in mInfos)
            {
                var t = (T)Enum.Parse(type, mInfo.Name);
                lstEnum.Add(t);
            }
            return lstEnum;
        }

        public static Hashtable ToHashtable(this NameValueCollection param)
        {
            Hashtable ht = new Hashtable();
            foreach (string key in param.AllKeys)
            {
                string name = key;
                string value = param[key];
                ht.Add(name, value);
            }
            return ht;
        }
        public static List<Hashtable> ConvertHashtable(this DataTable data, params string[] excludeColNames)
        {
            List<Hashtable> lstHt = new List<Hashtable>();
            foreach (DataRow dr in data.Rows)
            {
                Hashtable ht = new Hashtable(StringComparer.OrdinalIgnoreCase);
                foreach (DataColumn dc in data.Columns)
                {
                    if (excludeColNames != null && excludeColNames.Contains(dc.ColumnName, StringComparer.OrdinalIgnoreCase))
                    {
                        continue;
                    }
                    object value = dr[dc.ColumnName];
                    ht.Add(dc.ColumnName, value);
                }
                lstHt.Add(ht);
            }
            return lstHt;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="data"></param>
        /// <param name="columnName"></param>
        /// <returns></returns>
        public static List<T> GetFirstCol<T>(this DataTable data, string columnName = "")
        {
            List<T> lst = new List<T>();
            if (data == null || data.Rows.Count <= 0)
            {
                return lst;
            }
            else
            {
                foreach (DataRow dr in data.Rows)
                {
                    if (!string.IsNullOrWhiteSpace(columnName))
                    {
                        if (dr[columnName] != null)
                        {
                            T t = (T)Convert.ChangeType(dr[columnName], typeof(T));
                            lst.Add(t);
                        }
                    }
                    else
                    {
                        if (dr[0] != null)
                        {
                            T t = (T)Convert.ChangeType(dr[0], typeof(T));
                            lst.Add(t);
                        }
                    }
                }
            }
            return lst;
        }


        public static Dictionary<TKey, TVal> GetDict<TKey, TVal>(this DataTable data, string ColumnNameKey, string ColumnVal)
        {
            Dictionary<TKey, TVal> dict = new Dictionary<TKey, TVal>();
            if (data == null || data.Rows.Count <= 0)
            {
                return new Dictionary<TKey, TVal>();
            }
            else
            {
                foreach (DataRow dr in data.Rows)
                {
                    TKey k = Util.ChangeType<TKey>(dr[ColumnNameKey]);
                    TVal v = Util.ChangeType<TVal>(dr[ColumnVal]);
                    dict.Add(k, v);
                }
            }
            return dict;
        }

        public static T ConvertToObjectFromDR<T>(this DataRow row)
        {
            T obj = (T)Activator.CreateInstance(typeof(T));
            obj = ConvertToObjectFromDR<T>(row, obj);
            return obj;
        }
        /// <summary>
        /// 将数据库中的值转换为对象
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="dt"></param>
        /// <returns></returns>
        private static T ConvertToObjectFromDR<T>(this DataRow row, T obj)
        {
            Type type = obj.GetType();
            System.Reflection.PropertyInfo[] propInfo = type.GetProperties();
            for (int i = 0; i < propInfo.Length; i++)
            {
                if (row.Table.Columns[propInfo[i].Name] != null && row[propInfo[i].Name] != System.DBNull.Value)
                {
                    object objVal = row[propInfo[i].Name];
                    Type typeVal = Nullable.GetUnderlyingType(propInfo[i].PropertyType) ?? propInfo[i].PropertyType;
                    int mark = 0;
                    try
                    {
                        if (typeVal.Name == "Guid")
                        {
                            mark = 1;
                            propInfo[i].SetValue(obj, Guid.Parse(objVal.ToString()), null);
                        }
                        else
                        {
                            if (typeVal.IsEnum && objVal != null)
                            {
                                Type tyEnum = Enum.GetUnderlyingType(typeVal);
                                if (tyEnum.IsAssignableFrom(typeof(int)))
                                {
                                    mark = 2;
                                    propInfo[i].SetValue(obj, Enum.Parse(typeVal, objVal.ToString()), null);
                                }
                                else
                                {
                                    mark = 3;
                                    propInfo[i].SetValue(obj, Convert.ChangeType(objVal, typeVal), null);
                                }
                            }
                            else
                            {
                                if (objVal == null || string.IsNullOrWhiteSpace(objVal.ToString()))
                                {
                                    mark = 4;
                                    if (propInfo[i].PropertyType.IsNullableType())
                                    {
                                        objVal = null;
                                    }
                                    propInfo[i].SetValue(obj, objVal, null);
                                }
                                else
                                {
                                    mark = 5;
                                    propInfo[i].SetValue(obj, Convert.ChangeType(objVal, typeVal), null);
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        throw new ArgumentException("SetValue出错！(" + mark + ")", propInfo[i].Name + ":" + objVal, ex);
                    }
                }
            }
            return obj;
        }

        /// <summary>
        /// 将datatable转换为List对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="type"></param>
        /// <param name="this"></param>
        /// <returns></returns>
        public static List<T> ConvertToListObject<T>(this DataTable @this)
        {

            List<T> objs = new List<T>();
            for (int i = 0; i < @this.Rows.Count; i++)
            {
                T obj = (T)Activator.CreateInstance(typeof(T));
                obj = ConvertToObjectFromDR(@this.Rows[i], obj);
                objs.Add(obj);
            }
            return objs;
        }

        public static int DataLength(this string @this)
        {
            if (string.IsNullOrEmpty(@this))
            {
                return 0;
            }
            int lng = 0;
            for (int i = 0; i < @this.Length; i++)
            {
                byte[] b = System.Text.Encoding.Default.GetBytes(@this.Substring(i, 1));
                if (b.Length > 1)
                    lng += 2;
                else
                    lng += 1;
            }
            return lng;
        }


        /// <summary>
        /// 获取首行数据
        /// </summary>
        /// <param name="this"></param>
        /// <returns></returns>
        public static DataRow FirstRow(this DataTable @this)
        {
            if (@this == null)
            {
                throw new ArgumentNullException("DataTable不能为null");
            }
            return @this.Rows[0];
        }

        /// <summary>
        /// 获取最后一行数据
        /// </summary>
        /// <param name="this"></param>
        /// <returns></returns>
        public static DataRow LastRow(this DataTable @this)
        {
            if (@this == null)
            {
                throw new ArgumentNullException("DataTable不能为null");
            }
            return @this.Rows[@this.Rows.Count - 1];
        }

        /// <summary>
        ///给当前DataTable增加列名 
        /// </summary>
        /// <param name="this"></param>
        /// <param name="columnNames"></param>
        /// <returns></returns>
        public static DataTable AddColumns(this DataTable @this, params string[] columnNames)
        {
            if (@this == null)
            {
                @this = new DataTable();
            }
            if (columnNames != null && columnNames.Length > 0)
            {
                @this.Columns.AddRange(columnNames.Select(t => new DataColumn(t)).ToArray());
            }
            return @this;
        }

        public static DataColumn[] ToArray(this DataColumnCollection columnCollection)
        {
            List<DataColumn> lstDC = new List<DataColumn>();
            foreach (DataColumn dc in columnCollection)
            {
                lstDC.Add(dc);
            }
            return lstDC.ToArray();
        }
        public static void AddRange(this DataRowCollection @this, IEnumerable<DataRow> drs)
        {
            foreach (DataRow dr in drs)
            {
                @this.Add(dr.ItemArray);
            }
        }

        /// <summary>
        /// 将DataRow转为 dynamic 类型对象
        /// </summary>
        /// <param name="this"></param>
        /// <returns></returns>
        public static dynamic ToExpandoObject(this DataRow @this)
        {
            dynamic entity = new ExpandoObject();
            var expandoDict = (IDictionary<string, object>)entity;
            foreach (DataColumn column in @this.Table.Columns)
            {
                expandoDict.Add(column.ColumnName, @this[column]);
            }
            return expandoDict;
        }
        /// <summary>
        /// 获取List dynamic> 动态类型数据
        /// </summary>
        /// <param name="this"></param>
        /// <returns></returns>
        public static IEnumerable<dynamic> ToExpandoObjects(this DataTable @this)
        {
            var list = new List<dynamic>();

            foreach (DataRow dr in @this.Rows)
            {
                dynamic entity = new ExpandoObject();
                var expandoDict = (IDictionary<string, object>)entity;

                foreach (DataColumn column in @this.Columns)
                {
                    expandoDict.Add(column.ColumnName, dr[column]);
                }
                list.Add(entity);
            }
            return list;
        }





    }
}
